package com.lwl.java.base;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author lwl
 * @Description 三个线程交替打印
 * @date 2025/9/7 10:10
 */
public class AlternatePrintingThreeThread {
    Lock lock = new ReentrantLock();
    Condition condition1 = lock.newCondition();
    Condition condition2 = lock.newCondition();
    Condition condition3 = lock.newCondition();
    int printNumber = 1;
    Object lockObj = new Object();
    private final int threadNum = 3;

    public static void main(String[] args) throws InterruptedException {
//        test01();
        AlternatePrintingThreeThread ap = new AlternatePrintingThreeThread();
        new Thread(() -> ap.printNumbers(1), "线程1").start();
        new Thread(() -> ap.printNumbers(2), "线程2").start();
        new Thread(() -> ap.printNumbers(3), "线程3").start();
    }

    /**
     * 交替打印数字
     *
     * @param no 当前线程序号
     */
    public void printNumbers(int no) {
        try {
            while (printNumber <= 100) {
                synchronized (lockObj) {
                    while ((printNumber % threadNum) + 1 != no) {
                        lockObj.wait();
                    }
                    // 走到这里是线程独占的
                    if (printNumber > 100) {
                        break;
                    }
                    System.out.println(Thread.currentThread().getName() + " : " + printNumber++);
                    lockObj.notifyAll();
                }
            }
            System.out.println(Thread.currentThread().getName() + " 打印结束 ～");
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    private static void test01() throws InterruptedException {
        AlternatePrintingThreeThread printProcess = new AlternatePrintingThreeThread();
        new Thread(printProcess::printFirst).start();
        new Thread(printProcess::printSecond).start();
        new Thread(printProcess::printThird).start();
        Thread.sleep(1000);
        new Thread(printProcess::start).start();
    }

    public void start() {
        lock.lock();
        try {
            System.out.println("开始打印，唤醒 condition 1");
            condition1.signal();
        } finally {
            lock.unlock();
        }
    }

    public void printFirst() {
        while (printNumber <= 100) {
            lock.lock();
            try {
                condition1.await();
                if (printNumber > 100) {
                    condition3.signal();
                    break;
                }
                System.out.println(Thread.currentThread().getName() + " : " + printNumber++);
                condition2.signal();
            } catch (InterruptedException e) {
                System.out.println("程序中断");
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }
        }
        System.out.println(Thread.currentThread().getName() + " 打印结束 ～");

    }

    public void printSecond() {
        while (printNumber <= 100) {
            lock.lock();
            try {
                condition2.await();
                if (printNumber > 100) {
                    condition3.signal();
                    break;
                }
                System.out.println(Thread.currentThread().getName() + " : " + printNumber++);
                condition3.signal();
            } catch (InterruptedException e) {
                System.out.println("程序中断");
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }
        }
        System.out.println(Thread.currentThread().getName() + " 打印结束 ～");
    }

    public void printThird() {
        while (printNumber <= 100) {
            lock.lock();
            try {
                condition3.await();
                if (printNumber > 100) {
                    condition1.signal();
                    break;
                }
                System.out.println(Thread.currentThread().getName() + " : " + printNumber++);
                condition1.signal();
            } catch (InterruptedException e) {
                System.out.println("程序中断");
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }
        }
        System.out.println(Thread.currentThread().getName() + " 打印结束 ～");
    }
}
